import os
import os
import uuid
import hashlib
import datetime
import logging
from flask import Flask, render_template, request, redirect, url_for, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_cors import CORS
import jwt
from functools import wraps

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

# JWT配置
JWT_SECRET_KEY = os.environ.get('JWT_SECRET_KEY') or 'your-secret-key-here'
JWT_EXPIRATION = 24 * 60 * 60  # 24小时

# 初始化Flask应用
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///data/card_system.db'  # SQLite数据库，存储在数据目录中
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)

# 初始化CORS
CORS(app, resources={r"/api/*": {"origins": "*"}})

# 管理员表
class Admin(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(50), unique=True, nullable=False)
    password_hash = db.Column(db.String(128), nullable=False)
    
    def set_password(self, password):
        self.password_hash = hashlib.sha256(password.encode()).hexdigest()
        
    def check_password(self, password):
        return self.password_hash == hashlib.sha256(password.encode()).hexdigest()

# 应用表
class Application(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), unique=True, nullable=False)
    description = db.Column(db.String(200))

# 卡密表
class CardKey(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    key = db.Column(db.String(50), unique=True, nullable=False)  # 卡密字符串
    created_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)
    expires_at = db.Column(db.DateTime, nullable=True)  # 有效期，激活后设置
    valid_days = db.Column(db.Integer, nullable=False)  # 有效天数
    is_activated = db.Column(db.Boolean, default=False)
    activation_time = db.Column(db.DateTime)
    mainboard_serial = db.Column(db.String(100))  # 绑定的主板序列号
    mac_address = db.Column(db.String(100))  # 绑定的MAC地址
    app_name = db.Column(db.String(100))  # 应用名称
    machine_info = db.relationship('MachineInfo', backref='card_key', uselist=False)

# 机器信息表
class MachineInfo(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    card_key_id = db.Column(db.Integer, db.ForeignKey('card_key.id'), unique=True, nullable=False)
    os_version = db.Column(db.String(100))  # 操作系统版本
    mainboard_serial = db.Column(db.String(100))  # 主板序列号
    mac_address = db.Column(db.String(100))  # MAC地址
    activated_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)
    ip_address = db.Column(db.String(50))  # IP地址
    ip_location = db.Column(db.String(100))  # IP归属地

# JWT认证装饰器
def token_required(f):
    logger.info('调用token_required装饰器')
    @wraps(f)
    def decorated_function(*args, **kwargs):
        token = request.headers.get('Authorization')
        if not token:
            return jsonify({'success': False, 'message': '认证令牌缺失'}), 401

        try:
            # 移除Bearer前缀
            if token.startswith('Bearer '):
                token = token[7:]
            data = jwt.decode(token, JWT_SECRET_KEY, algorithms=['HS256'])
            current_admin = Admin.query.get(data['admin_id'])
        except:
            return jsonify({'success': False, 'message': '无效的认证令牌'}), 401

        return f(current_admin, *args, **kwargs)
    return decorated_function

# 生成卡密
def generate_card_key(length=16):
    logger.info(f'调用generate_card_key函数，长度: {length}')
    """生成指定长度的随机卡密，格式为XXXX-XXXX-XXXX-XXXX"""
    key = str(uuid.uuid4()).replace('-', '').upper()[:length]
    # 格式化卡密，每4个字符一组
    return '-'.join([key[i:i+4] for i in range(0, len(key), 4)])

# 初始化数据库和默认数据
def init_db():
    logger.info('调用init_db函数，初始化数据库')
    with app.app_context():
        db.create_all()
        # 检查是否已有管理员
        if not Admin.query.first():
            admin = Admin(username='admin')
            admin.set_password('admin123')  # 默认密码
            db.session.add(admin)
        
        # 检查是否已有应用
        if not Application.query.first():
            app1 = Application(name='微加加', description='微加加应用程序')
            app2 = Application(name='微群拓客宝', description='微群拓客宝应用程序')
            db.session.add(app1)
            db.session.add(app2)
            
        db.session.commit()

# 路由：登录API
@app.route('/api/login', methods=['POST'])
def login():
    logger.info('调用login函数，处理登录请求')
    data = request.json
    username = data.get('username')
    password = data.get('password')
    
    if not username or not password:
        return jsonify({'success': False, 'message': '用户名和密码不能为空'}), 400
    
    admin = Admin.query.filter_by(username=username).first()
    
    if admin and admin.check_password(password):
        # 生成JWT令牌
        payload = {
            'admin_id': admin.id,
            'exp': datetime.datetime.utcnow() + datetime.timedelta(seconds=JWT_EXPIRATION)
        }
        token = jwt.encode(payload, JWT_SECRET_KEY, algorithm='HS256')
        
        return jsonify({
            'success': True,
            'message': '登录成功',
            'token': token,
            'admin': {
                'id': admin.id,
                'username': admin.username
            }
        }), 200
    else:
        return jsonify({'success': False, 'message': '用户名或密码错误'}), 401

# 路由：退出登录API
@app.route('/api/logout', methods=['POST'])
@token_required
def logout(current_admin):
    logger.info(f'调用logout函数，管理员 {current_admin.username} 退出登录')
    # 前端处理令牌失效
    return jsonify({'success': True, 'message': '退出成功'}), 200

# 路由：仪表盘API
@app.route('/api/dashboard')
@token_required
def dashboard(current_admin):
    logger.info(f'调用dashboard函数，管理员 {current_admin.username} 访问仪表盘')
    # 获取统计信息
    total_keys = CardKey.query.count()
    activated_keys = CardKey.query.filter_by(is_activated=True).count()
    expired_keys = CardKey.query.filter(CardKey.expires_at < datetime.datetime.utcnow()).count()
    unactivated_keys = total_keys - activated_keys - expired_keys
    apps = Application.query.all()
    
    app_stats = []
    for app in apps:
        app_keys = CardKey.query.filter_by(app_name=app.name).count()
        app_activated = CardKey.query.filter_by(app_name=app.name, is_activated=True).count()
        app_expired = CardKey.query.filter(CardKey.app_name == app.name, CardKey.expires_at < datetime.datetime.utcnow()).count()
        app_stats.append({
            'id': app.id,
            'name': app.name,
            'total': app_keys,
            'activated': app_activated,
            'expired': app_expired,
            'unactivated': app_keys - app_activated - app_expired
        })
    
    return jsonify({
        'success': True,
        'data': {
            'total_keys': total_keys,
            'activated_keys': activated_keys,
            'expired_keys': expired_keys,
            'unactivated_keys': unactivated_keys,
            'app_stats': app_stats
        }
    }), 200

# 路由：获取应用列表API
@app.route('/api/apps')
@token_required
def get_apps(current_admin):
    logger.info(f'调用get_apps函数，管理员 {current_admin.username} 获取应用列表')
    apps = Application.query.all()
    apps_list = [{
        'id': app.id,
        'name': app.name,
        'description': app.description
    } for app in apps]
    
    return jsonify({
        'success': True,
        'data': apps_list
    }), 200

# 路由：生成卡密API
@app.route('/api/generate', methods=['POST'])
@token_required
def generate_keys(current_admin):
    logger.info(f'调用generate_keys函数，管理员 {current_admin.username} 生成卡密')
    data = request.json
    count = int(data.get('count', 1))
    duration_type = data.get('duration_type', 'month')  # 默认月卡
    days = 0
    
    # 根据时长类型计算天数
    if duration_type == 'day':
        days = 1
    elif duration_type == 'week':
        days = 7
    elif duration_type == 'month':
        days = 30
    elif duration_type == 'quarter':
        days = 90
    elif duration_type == 'half_year':
        days = 180
    elif duration_type == 'year':
        days = 365
    elif duration_type == 'permanent':
        days = 0  # 永久卡特殊标记
    else:
        return jsonify({'success': False, 'message': '无效的时长类型'}), 400
    
    if count <= 0 or count > 100:
        return jsonify({'success': False, 'message': '生成数量必须在1-100之间'}), 400
    
    if days < 0 or (days > 0 and days > 365):
        return jsonify({'success': False, 'message': '有效期必须在1-365天之间或为永久卡'}), 400
    
    generated_keys = []
    for _ in range(count):
        # 生成唯一卡密
        while True:
            key = generate_card_key()
            if not CardKey.query.filter_by(key=key).first():
                break
        
        # 创建卡密记录
        card_key = CardKey(
            key=key,
            valid_days=days
        )
        db.session.add(card_key)
        generated_keys.append(key)
    
    db.session.commit()
    
    return jsonify({
        'success': True,
        'message': f'成功生成{count}个卡密',
        'data': generated_keys
    }), 200

# 路由：卡密列表API
@app.route('/api/keys')
@token_required
def get_card_keys(current_admin):
    logger.info(f'调用get_card_keys函数，管理员 {current_admin.username} 获取卡密列表')
    app_id = request.args.get('appId', '')
    status = request.args.get('status', '')
    page = int(request.args.get('page', 1))
    page_size = int(request.args.get('page_size', 10))
    offset = (page - 1) * page_size
    
    # 构建查询
    query = CardKey.query

    # 按应用筛选
    if app_id:  # 确保app_id不为空字符串
        app = Application.query.get(app_id)
        if app:
            query = query.filter_by(app_name=app.name)

    # 按状态筛选
    if status == 'activated':
        query = query.filter_by(is_activated=True)
    elif status == 'unactivated':
        query = query.filter_by(is_activated=False)
    elif status == 'expired':
        query = query.filter(CardKey.expires_at < datetime.datetime.utcnow())
    
    # 获取总数
    total = query.count()
    
    # 分页和排序
    card_keys = query.order_by(CardKey.created_at.desc()).offset(offset).limit(page_size).all()
    
    # 格式化结果
    result = []
    for key in card_keys:
        now = datetime.datetime.utcnow()
        status_text = ''
        
        if key.expires_at is not None and key.expires_at < now:
            status_text = '已过期'
        elif key.is_activated:
            status_text = '已激活'
        else:
            status_text = '未激活'
        
        result.append({
            'id': key.id,
            'key': key.key,
            'valid_days': key.valid_days,
            'created_at': key.created_at.isoformat(),
            'expires_at': key.expires_at.isoformat() if key.expires_at is not None else None,
            'is_activated': key.is_activated,
            'activation_time': key.activation_time.isoformat() if key.activation_time else None,
            'app_name': key.app_name,
            'status': 'expired' if (key.expires_at is not None and key.expires_at < now) else ('activated' if key.is_activated else 'unactivated'),
            'status_text': status_text
        })
    
    return jsonify({
        'success': True,
        'data': {
            'items': result,
            'total': total,
            'page': page,
            'page_size': page_size
        }
    }), 200

# 路由：卡密详情API
@app.route('/api/keys/<int:key_id>')
@token_required
def get_card_key_detail(current_admin, key_id):
    logger.info(f'调用get_card_key_detail函数，管理员 {current_admin.username} 查看卡密 {key_id} 详情')
    card_key = CardKey.query.get_or_404(key_id)
    
    now = datetime.datetime.utcnow()
    status_text = ''
    
    # 检查expires_at是否为None，避免类型错误
    if card_key.expires_at is not None and card_key.expires_at < now:
        status_text = '已过期'
    elif card_key.is_activated:
        status_text = '已激活'
    else:
        status_text = '未激活'
    
    # 获取机器信息
    machine_info = None
    if card_key.machine_info:
        machine_info = {
            'os_version': card_key.machine_info.os_version,
            'mainboard_serial': card_key.machine_info.mainboard_serial,
            'mac_address': card_key.machine_info.mac_address,
            'activated_at': card_key.machine_info.activated_at.isoformat(),
            'ip_address': card_key.machine_info.ip_address,
            'ip_location': card_key.machine_info.ip_location
        }
    
    result = {
        'id': card_key.id,
        'key': card_key.key,
        'valid_days': card_key.valid_days,
        'app_name': card_key.app_name,
        'created_at': card_key.created_at.isoformat(),
        'expires_at': card_key.expires_at.isoformat() if card_key.expires_at is not None else None,
        'is_activated': card_key.is_activated,
        'activation_time': card_key.activation_time.isoformat() if card_key.activation_time else None,
        'machine_id': card_key.machine_info.id if card_key.machine_info else None,
        'machine_info': machine_info,
        'status': 'expired' if (card_key.expires_at is not None and card_key.expires_at < now) else ('activated' if card_key.is_activated else 'unactivated'),
        'status_text': status_text
    }
    
    return jsonify({
        'success': True,
        'data': result
    }), 200

# 路由：删除卡密API
@app.route('/api/keys/<int:key_id>', methods=['DELETE'])
@token_required
def delete_card_key(current_admin, key_id):
    logger.info(f'调用delete_card_key函数，管理员 {current_admin.username} 删除卡密 {key_id}')
    card_key = CardKey.query.get_or_404(key_id)
    
    # 级联删除相关的机器信息
    if card_key.machine_info:
        db.session.delete(card_key.machine_info)
    
    # 删除卡密
    db.session.delete(card_key)
    db.session.commit()
    
    return jsonify({
        'success': True,
        'message': '卡密已成功删除'
    }), 200

# 导入requests库用于IP归属地查询
import requests

# API：激活卡密（供客户端使用）
@app.route('/api/activate', methods=['POST'])
def activate():
    logger.info('调用activate函数，处理卡密激活请求')
    data = request.json
    license_key = data.get('license_key')
    mainboard_serial = data.get('mainboard_serial')
    mac_address = data.get('mac_address')
    windows_version = data.get('windows_version')
    app_name = data.get('app_name')
    
    # 获取客户端IP地址
    client_ip = request.remote_addr
    logger.info(f'客户端IP地址: {client_ip}')
    
    # 查询IP归属地
    ip_location = '未知'
    try:
        response = requests.get(f'http://ip-api.com/json/{client_ip}?lang=zh-CN')
        if response.status_code == 200:
            ip_data = response.json()
            if ip_data.get('status') == 'success':
                ip_location = f'{ip_data.get("country", "")} {ip_data.get("regionName", "")} {ip_data.get("city", "")}'
                logger.info(f'IP归属地: {ip_location}')
    except Exception as e:
        logger.error(f'IP归属地查询失败: {str(e)}')
    
    # 查找卡密
    card_key = CardKey.query.filter_by(key=license_key).first()
    if not card_key:
        return jsonify({'success': False, 'message': '无效的卡密'})
    
    # 检查是否已激活
    if card_key.is_activated:
        # 如果是同一台机器，允许继续使用
        if card_key.mainboard_serial == mainboard_serial and card_key.mac_address == mac_address:
            # 检查expires_at是否为None（永久卡）
            expires_at = card_key.expires_at.isoformat() if card_key.expires_at else 'permanent'
            return jsonify({
                'success': True,
                'message': '卡密已在该机器上激活',
                'expires_at': expires_at
            })
        else:
            return jsonify({'success': False, 'message': '卡密已绑定到其他机器'})
    
    # 检查是否过期
    if card_key.expires_at is not None and card_key.expires_at < datetime.datetime.utcnow():
        return jsonify({'success': False, 'message': '卡密已过期'})
    
    # 检查是否已绑定到其他机器
    if card_key.mainboard_serial and (card_key.mainboard_serial != mainboard_serial or card_key.mac_address != mac_address):
        return jsonify({'success': False, 'message': '卡密已绑定到其他机器'})
    
    # 激活卡密
    card_key.is_activated = True
    activation_time = datetime.datetime.utcnow()
    card_key.activation_time = activation_time
    # 根据valid_days计算有效期
    # 永久卡不设置过期时间
    if card_key.valid_days > 0:
        card_key.expires_at = activation_time + datetime.timedelta(days=card_key.valid_days)
    else:
        card_key.expires_at = None
    card_key.mainboard_serial = mainboard_serial
    card_key.mac_address = mac_address
    card_key.app_name = app_name
    
    # 保存机器信息
    machine = MachineInfo(
        card_key_id=card_key.id,
        os_version=windows_version,
        mainboard_serial=mainboard_serial,
        mac_address=mac_address,
        ip_address=client_ip,
        ip_location=ip_location
    )
    db.session.add(machine)
    db.session.commit()
    
    return jsonify({
        'success': True, 
        'message': '激活成功',
        'expires_at': card_key.expires_at.isoformat()
    })

# API：检查卡密状态（供客户端使用）
@app.route('/api/check-key', methods=['POST'])
def check_key():
    logger.info('调用check_key函数，检查卡密状态')
    data = request.json
    key = data.get('key')
    machine_id = data.get('machine_id')
    
    if not key or not machine_id:
        return jsonify({'success': False, 'message': '缺少参数'})
    
    card_key = CardKey.query.filter_by(key=key).first()
    if not card_key:
        return jsonify({'success': False, 'message': '无效的卡密'})
    
    if not card_key.is_activated:
        return jsonify({'success': False, 'message': '卡密未激活'})
    
    if card_key.machine_id != machine_id:
        return jsonify({'success': False, 'message': '卡密已绑定到其他设备'})
    
    if card_key.expires_at < datetime.datetime.utcnow():
        return jsonify({'success': False, 'message': '卡密已过期'})
    
    return jsonify({
        'success': True, 
        'message': '卡密有效',
        'app_name': card_key.app_name,
        'expires_at': card_key.expires_at.isoformat()
    })

# 初始化数据库
init_db()

if __name__ == '__main__':
    app.run(debug=True)
